package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

// 游戏常量
const (
	Empty     = " "
	PlayerX   = "X"
	PlayerO   = "O"
	BoardSize = 3
)

// 游戏状态
type GameState int

const (
	Playing GameState = iota
	XWins
	OWins
	Draw
)

// 游戏结构体
type Game struct {
	board  [][]string
	player string
	moves  int
	state  GameState
}

// 新建游戏
func NewGame() *Game {
	board := make([][]string, BoardSize)
	for i := range board {
		board[i] = make([]string, BoardSize)
		for j := range board[i] {
			board[i][j] = Empty
		}
	}

	return &Game{
		board:  board,
		player: PlayerX,
		moves:  0,
		state:  Playing,
	}
}

// 打印游戏板
func (g *Game) PrintBoard() {
	fmt.Println("\n   1   2   3")
	fmt.Println(" +---+---+---+")
	for i, row := range g.board {
		fmt.Printf("%d|", i+1)
		for _, cell := range row {
			fmt.Printf(" %s |", cell)
		}
		fmt.Println("\n +---+---+---+")
	}
	fmt.Printf("当前玩家: %s\n", g.player)
}

// 检查移动是否有效
func (g *Game) IsValidMove(row, col int) bool {
	if row < 0 || row >= BoardSize || col < 0 || col >= BoardSize {
		return false
	}
	return g.board[row][col] == Empty
}

// 执行移动
func (g *Game) MakeMove(row, col int) bool {
	if !g.IsValidMove(row, col) {
		return false
	}

	g.board[row][col] = g.player
	g.moves++

	// 检查游戏状态
	g.checkGameState()

	// 切换玩家
	if g.state == Playing {
		if g.player == PlayerX {
			g.player = PlayerO
		} else {
			g.player = PlayerX
		}
	}

	return true
}

// 检查游戏状态
func (g *Game) checkGameState() {
	// 检查行和列
	for i := 0; i < BoardSize; i++ {
		if g.board[i][0] != Empty && g.board[i][0] == g.board[i][1] && g.board[i][1] == g.board[i][2] {
			if g.board[i][0] == PlayerX {
				g.state = XWins
			} else {
				g.state = OWins
			}
			return
		}

		if g.board[0][i] != Empty && g.board[0][i] == g.board[1][i] && g.board[1][i] == g.board[2][i] {
			if g.board[0][i] == PlayerX {
				g.state = XWins
			} else {
				g.state = OWins
			}
			return
		}
	}

	// 检查对角线
	if g.board[0][0] != Empty && g.board[0][0] == g.board[1][1] && g.board[1][1] == g.board[2][2] {
		if g.board[0][0] == PlayerX {
			g.state = XWins
		} else {
			g.state = OWins
		}
		return
	}

	if g.board[0][2] != Empty && g.board[0][2] == g.board[1][1] && g.board[1][1] == g.board[2][0] {
		if g.board[0][2] == PlayerX {
			g.state = XWins
		} else {
			g.state = OWins
		}
		return
	}

	// 检查平局
	if g.moves == BoardSize*BoardSize {
		g.state = Draw
		return
	}

	g.state = Playing
}

// 获取游戏状态描述
func (g *Game) GetStateDescription() string {
	switch g.state {
	case XWins:
		return "玩家 X 获胜！🎉"
	case OWins:
		return "玩家 O 获胜！🎉"
	case Draw:
		return "平局！🤝"
	default:
		return "游戏进行中..."
	}
}

// 显示游戏帮助
func ShowHelp() {
	fmt.Println(`
=== 井字棋游戏帮助 ===
游戏规则:
- 两个玩家轮流在 3x3 的棋盘上放置自己的标记
- 玩家 X 先手，玩家 O 后手
- 先在任意一行、一列或对角线上连成一条线的玩家获胜
- 如果棋盘填满无人获胜，则为平局

操作方法:
- 输入行号和列号来选择位置 (例如: 1 2)
- 输入 'help' 显示帮助
- 输入 'quit' 退出游戏
- 输入 'restart' 重新开始游戏

棋盘坐标:
   1   2   3
1|   |   |   |
2|   |   |   |
3|   |   |   |
	`)
}

// 获取玩家输入
func GetPlayerInput() (int, int, bool) {
	scanner := bufio.NewScanner(os.Stdin)

	for {
		fmt.Print("请输入行和列 (例如: 1 2): ")
		scanner.Scan()
		input := strings.TrimSpace(scanner.Text())

		// 检查特殊命令
		if input == "quit" || input == "exit" {
			return -1, -1, true
		}
		if input == "help" {
			ShowHelp()
			continue
		}
		if input == "restart" {
			return -2, -2, false
		}

		// 解析坐标
		parts := strings.Fields(input)
		if len(parts) != 2 {
			fmt.Println("❌ 输入格式错误！请输入两个数字，用空格分隔。")
			continue
		}

		row, err1 := strconv.Atoi(parts[0])
		col, err2 := strconv.Atoi(parts[1])

		if err1 != nil || err2 != nil {
			fmt.Println("❌ 请输入有效的数字！")
			continue
		}

		// 转换为0-based索引
		row--
		col--

		if row < 0 || row >= BoardSize || col < 0 || col >= BoardSize {
			fmt.Printf("❌ 坐标超出范围！请输入 1-%d 之间的数字。\n", BoardSize)
			continue
		}

		return row, col, false
	}
}

// 显示游戏标题
func ShowTitle() {
	fmt.Println(`
████████╗██╗ ██████╗ ████████╗ █████╗ ███████╗████████╗
╚══██╔══╝██║██╔════╝ ╚══██╔══╝██╔══██╗██╔════╝╚══██╔══╝
   ██║   ██║██║         ██║   ███████║█████╗     ██║   
   ██║   ██║██║         ██║   ██╔══██║██╔══╝     ██║   
   ██║   ██║╚██████╗    ██║   ██║  ██║███████╗   ██║   
   ╚═╝   ╚═╝ ╚═════╝    ╚═╝   ╚═╝  ╚═╝╚══════╝   ╚═╝   
	`)
	fmt.Println("欢迎来到命令行井字棋游戏！")
	fmt.Println("输入 'help' 查看游戏帮助")
}

// 主游戏循环
func main() {
	ShowTitle()
	ShowHelp()

	for {
		game := NewGame()
		gameLoop(game)

		// 询问是否再玩一次
		fmt.Print("\n是否再玩一次？(y/n): ")
		scanner := bufio.NewScanner(os.Stdin)
		scanner.Scan()
		answer := strings.TrimSpace(strings.ToLower(scanner.Text()))

		if answer != "y" && answer != "yes" {
			fmt.Println("感谢游戏！再见！👋")
			break
		}
		fmt.Println("开始新游戏...")
	}
}

// 游戏主循环
func gameLoop(game *Game) {
	for {
		game.PrintBoard()

		row, col, shouldQuit := GetPlayerInput()

		if shouldQuit {
			fmt.Println("游戏结束！")
			os.Exit(0)
		}

		if row == -2 && col == -2 {
			fmt.Println("重新开始游戏...")
			return
		}

		if !game.MakeMove(row, col) {
			fmt.Println("❌ 该位置已被占用或无效，请重新选择！")
			continue
		}

		// 检查游戏是否结束
		if game.state != Playing {
			game.PrintBoard()
			fmt.Printf("\n%s\n", game.GetStateDescription())
			break
		}
	}
}
